﻿using System;
using System.Collections.Generic;
using System.Linq;
using CLM.Gestao.Interfaces;
using CLM.Gestao.Administrador.DAL;
using CLM.Gestao.Importacao;
using System.Data;

namespace CLM.Gestao.Administrador.BLL
{
    public class ProdutoFamiliaDriverRateioValor : ProdutoFamiliaDriverRateioValorBLO<TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR>
    {
        #region Propriedades

        public int IdProdutoFamilia { get; set; }
        public string NomeProdutoFamilia { get; set; }
        public int IdPeriodo { get; set; }
        public decimal ValorPromocaoGrade { get; set; }

        #endregion Propriedades

        #region Conversões

        private List<TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR> ConvertToEDM(List<Lista> pLista)
        {
            List<TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR> List = (from l in pLista
                                                                 select new TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR
                                                                 {
                                                                     ID_PRODUTO_FAMILIA = l.IdProdutoFamilia,
                                                                     ID_PERIODO = l.IdPeriodo,
                                                                     VALOR_PROMOCAO_GRADE = l.ValorPromocaoGrade,
                                                                 }).ToList();
            return List;
        }

        private List<Lista> ConvertToContext(IQueryable<TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR> pContext)
        {
            List<Lista> List = (from l in pContext
                                select new Lista
                                {
                                    IdProdutoFamilia = l.ID_PRODUTO_FAMILIA,
                                    NomeProdutoFamilia = l.TB_PRODUTO_FAMILIA.NOME_PRODUTO_FAMILIA.Trim(),
                                    IdPeriodo = l.ID_PERIODO,
                                    ValorPromocaoGrade = l.VALOR_PROMOCAO_GRADE
                                }).ToList();
            return List;
        }

        #endregion Conversões

        #region CRUD
        /// <summary>
        /// Adiciona
        /// </summary>
        /// <param name="pLista">pLista</param>
        public void Add(List<Lista> pLista)
        {
            try
            {
                foreach (var item in ConvertToEDM(pLista))
                    base.Add(item);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Deleta
        /// </summary>
        /// <param name="pLista">pLista</param>
        public void Delete(List<Lista> pLista)
        {
            try
            {
                foreach (var item in ConvertToEDM(pLista))
                    base.Delete(item);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Atualiza
        /// </summary>
        /// <param name="pLista">pLista</param>
        public void Update(List<Lista> pLista)
        {
            try
            {
                foreach (var item in ConvertToEDM(pLista))
                    base.Update(item);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Efetua a pesquisa na tabela, filtrando as solicitações do usuário
        /// </summary>
        /// <param name="pPesquisa">pPesquisa</param>
        /// <returns>Lista</returns>
        private IQueryable<TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR> Get(Lista pPesquisa)
        {
            IQueryable<TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR> Consulta;

            Consulta = from p in GetAll()
                       select p;
            if (pPesquisa != null)
            {
                if (pPesquisa.IdProdutoFamilia > 0)
                    Consulta = from p in Consulta where p.ID_PRODUTO_FAMILIA == pPesquisa.IdProdutoFamilia select p;
            }
            return Consulta;
        }

        #endregion CRUD

        #region Retorna Listas e Itens

        public List<Lista> GetLista()
        {
            return GetLista(new Lista());
        }

        public List<Lista> GetLista(Lista pPesquisa)
        {
            var ListaProdutoFamilia = ConvertToContext(Get(pPesquisa));
            return ListaProdutoFamilia;
        }

        #endregion Retorna Listas e Itens

        #region Consultas


        #endregion Consultas

        #region Processos

        #region Importa Driver

        private DataSet dsProdutoDriver;
        private Importacao.Excel ExcelConnection;

        public void ImportaDriverPromocaoGrade(string pFileName, int pIdPeriodo)
        {
            ExcelConnection = new Importacao.Excel();
            dsProdutoDriver = null;

            ValidaLayoutImportacao(pFileName);
            ValidaDadosImportacao();
            AtualizaDriverGradePromocional(pIdPeriodo);
        }

        private void AtualizaDriverGradePromocional(int pIdPeriodo)
        {
            ProdutoFamiliaDriverRateioValor Driver = new ProdutoFamiliaDriverRateioValor();
            OnImportData(this, new ImportDataEventArgs("Importando valores de Driver Grade Promocional..."));

            // Dictionary de Produtos para recuperar o ID, utilizando o código
            ProdutoFamilia ProdutoFamilia = new ProdutoFamilia();
            var FamiliaProdutos = ProdutoFamilia.GetItens().ToDictionary(d => d.NomeProdutoFamilia);

            // Coluna A, C
            List<ProdutoFamiliaDriverRateioValor.Lista> DriverExcel = (from p in dsProdutoDriver.Tables[0].AsEnumerable()
                                                                join j in FamiliaProdutos.Select(s => s.Value)
                                                                on p.Field<string>("Familia Hyperion").Trim() equals j.NomeProdutoFamilia.Trim()
                                                                where j.IdProdutoFamilia != 0
                                                                select new ProdutoFamiliaDriverRateioValor.Lista
                                                                {
                                                                    IdProdutoFamilia = j.IdProdutoFamilia,
                                                                    IdPeriodo = pIdPeriodo,
                                                                    ValorPromocaoGrade = Convert.ToDecimal(p.Field<object>("Grade Promocional"))
                                                                }).Distinct().ToList();

            List<ProdutoFamiliaDriverRateioValor.Lista> DriverSQL = (from p in Driver.GetAll()
                                                              where p.ID_PERIODO == pIdPeriodo
                                                              select new ProdutoFamiliaDriverRateioValor.Lista
                                                              {
                                                                  IdProdutoFamiliaDriverRateioValor = p.ID_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR,
                                                                  IdProdutoFamilia = p.ID_PRODUTO_FAMILIA,
                                                                  IdPeriodo = p.ID_PERIODO,
                                                                  ValorPromocaoGrade = p.VALOR_PROMOCAO_GRADE
                                                              }).ToList();

            // Compara os arquivos do Excel com os existentes no Banco de Dados
            var Novos = (from p in DriverExcel
                         join db in DriverSQL
                         on p.IdProdutoFamilia equals db.IdProdutoFamilia
                         into driver
                         from db in driver.DefaultIfEmpty()
                         where db == null
                         select new ProdutoFamiliaDriverRateioValor.Lista
                         {
                             IdProdutoFamilia = p.IdProdutoFamilia,
                             IdPeriodo = p.IdPeriodo,
                             ValorPromocaoGrade = p.ValorPromocaoGrade
                         }).ToList();

            int i = 0;
            if (Novos != null && Novos.Count() > 0)
            {
                foreach (var item in Novos)
                {
                    Driver.Add(new TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR() { ID_PRODUTO_FAMILIA = item.IdProdutoFamilia, VALOR_PROMOCAO_GRADE = item.ValorPromocaoGrade, ID_PERIODO = (int)item.IdPeriodo });
                    i++;
                    OnImportData(this, new ImportDataEventArgs("Incluindo valores de Drivers Grade Promocional...", i, Novos.Count()));
                }
            }
            Driver.Save();

            List<ProdutoFamiliaDriverRateioValor.Lista> Alterados = (from p in DriverExcel
                                                              join db in DriverSQL
                                                              on p.IdProdutoFamilia equals db.IdProdutoFamilia
                                                              where p.ValorPromocaoGrade != db.ValorPromocaoGrade
                                                              select new ProdutoFamiliaDriverRateioValor.Lista
                                                              {
                                                                  IdProdutoFamiliaDriverRateioValor = db.IdProdutoFamiliaDriverRateioValor,
                                                                  IdProdutoFamilia = db.IdProdutoFamilia,
                                                                  IdPeriodo = p.IdPeriodo,
                                                                  ValorPromocaoGrade = p.ValorPromocaoGrade
                                                              }).ToList();
            i = 0;
            if (Alterados != null && Alterados.Count() > 0)
            {
                foreach (var item in Alterados)
                {
                    Driver.Update(new TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR()
                    {
                        ID_PRODUTO_FAMILIA = item.IdProdutoFamilia,
                        ID_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR = item.IdProdutoFamiliaDriverRateioValor,
                        ID_PERIODO = (int)item.IdPeriodo,
                        VALOR_PROMOCAO_GRADE = item.ValorPromocaoGrade
                    });
                    i++;
                    OnImportData(this, new ImportDataEventArgs("Alterando valores de Drivers Grade Promocional...", i, Alterados.Count()));
                }
            }
            Driver.Save();

            if (Novos != null && Novos.Count() == 0 && Alterados != null && Alterados.Count() == 0)
                OnImportData(this, new ImportDataEventArgs("Os valores de driver Grade Promocional para o período selecionado já estão importados. Não foram realizadas importações."));
            else
                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
        }

        private void ValidaLayoutImportacao(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsProdutoDriver = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { dsProdutoDriver = null; throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsProdutoDriver != null && dsProdutoDriver.Tables != null && dsProdutoDriver.Tables.Count > 0 && dsProdutoDriver.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsProdutoDriver.Tables[0].Rows[0].Field<object>("Familia Hyperion"); }
                catch { dsProdutoDriver = null; throw new Exception("A coluna (\"Familia Hyperion\") não foi encontrada no arquivo."); }

                try { var aux = dsProdutoDriver.Tables[0].Rows[0].Field<object>("Grade Promocional"); }
                catch { dsProdutoDriver = null; throw new Exception("A coluna (\"Grade Promocional\") não foi encontrada no arquivo."); }
            }
        }

        private void ValidaDadosImportacao()
        {
            if (dsProdutoDriver != null && dsProdutoDriver.Tables != null && dsProdutoDriver.Tables.Count > 0 && dsProdutoDriver.Tables[0].Rows.Count > 0)
            {
                var CustoUnitario = (from p in dsProdutoDriver.Tables[0].AsEnumerable()
                                     where (p.Field<object>("Familia Hyperion") != null) && (p.Field<object>("Grade Promocional") == null)
                                     select p).ToList();

                if (CustoUnitario != null && CustoUnitario.Count() > 0)
                {
                    dsProdutoDriver = null;
                    throw new Exception("Existem valores em branco.\nPor favor, reveja a planilha e reinicie a importação.");
                }
            }
        }

        #endregion Importa Driver Grade Promocional

        #endregion Processos

        #region Classes

        /// <summary>
        /// Lista com as propriedades da classe
        /// </summary>
        public class Lista
        {
            public int IdProdutoFamiliaDriverRateioValor { get; set; }
            public int IdProdutoFamilia { get; set; }
            public string NomeProdutoFamilia { get; set; }
            public int IdPeriodo { get; set; }
            public decimal ValorPromocaoGrade { get; set; }
        }

        #endregion Classes

        public event ImportDataEventHandler OnImportData;
    }

    public class ProdutoFamiliaDriverRateioValorBLO<T> where T : TB_PRODUTO_FAMILIA_DRIVER_RATEIO_VALOR
    {
        /// <summary>
        /// ProdutoFamiliaDAO
        /// </summary>
        private ProdutoFamiliaDriverRateioValorDAO<T> _base = new ProdutoFamiliaDriverRateioValorDAO<T>();

        /// <summary>
        /// Adiciona uma entidade no sistema
        /// </summary>
        /// <param name="pEntity">pEntity</param>
        /// <returns>Entidade</returns>
        public void Add(T pEntity)
        {
            Validate(pEntity);
            _base.Add(pEntity);
            //return _base.Save(pEntity);
        }

        /// <summary>
        /// Salva uma entidade do sistema
        /// </summary>
        /// <param name="pEntity">pEntity</param>
        /// <returns>Entidade</returns>
        public void Save()
        {
            _base.Save();
        }

        /// <summary>
        /// Deleta uma entidade do sistema
        /// </summary>
        /// <param name="pEntity">pEntity</param>
        public void Delete(T pEntity)
        {
            _base.Delete(pEntity);
        }

        /// <summary>
        /// Atualiza uma entidade do sistema
        /// </summary>
        /// <param name="pEntity">pEntity</param>
        /// <returns>Entidade</returns>
        public void Update(T pEntity)
        {
            Validate(pEntity);
            _base.Update(pEntity);
        }

        /// <summary>
        /// Recupera uma entidade do sistema
        /// </summary>
        /// <returns>Lista</returns>
        public IQueryable<T> GetAll()
        {
            return _base.GetAll();
        }

        /// <summary>
        /// Valida a consistência da Entidade antes de 'comitar' a transação
        /// </summary>
        /// <param name="pEntity">Entidade</param>
        public void Validate(T pEntity)
        {

        }
    }
}